package router

import (
	"net/http"

	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"

	"fmt"
	"go-web/config"
	"go-web/entity"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

func SetupRouter() *gin.Engine {
	r := gin.Default()
	db := InitDB()

	// CORS for https://example.com
	r.Use(cors.New(cors.Config{
		AllowOrigins:     []string{"http://localhost:5173"},
		AllowMethods:     []string{"PUT", "PATCH", "GET", "POST", "DELETE"},
		AllowHeaders:     []string{"Origin", "Content-Type", "Authorization"},
		ExposeHeaders:    []string{"Content-Length"},
		AllowCredentials: true,
	}))

	auth := r.Group("/api/auth")
	{
		// 登录
		auth.POST("/login", func(ctx *gin.Context) {
			// 获取参数
			var loginData entity.User
			if err := ctx.ShouldBindJSON(&loginData); err != nil {
				ctx.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "Invalid request body"})
				return
			}
			username := loginData.Username
			password := loginData.Password
			var user entity.User
			if err := db.Table("user").Where("username = ? and password = ?", username, password).First(&user).Error; err != nil {
				ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
					"code":    0,
					"message": "login failed",
				})
				fmt.Println(err)
			} else {
				ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
					"code":    1,
					"message": "login success",
				})
			}
			fmt.Println(user)
		})

		// 注册
		auth.POST("/register", func(ctx *gin.Context) {
			var dataInfo entity.User
			if err := ctx.ShouldBindJSON(&dataInfo); err != nil {
				ctx.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "Invalid request body"})
				return
			}
			var user entity.User
			username := dataInfo.Username
			password := dataInfo.Password
			if err := db.Table("user").Where("username = ?", username).First(&user).Error; err != nil {
				if err := db.Table("user").Create(&entity.User{Username: username, Password: password}).Error; err != nil {
					ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
						"code":    0,
						"message": "register failed",
					})
				} else {
					ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
						"code":    1,
						"message": "register success",
					})
				}
				fmt.Println(err)
			} else {
				ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
					"message": "The account has been registered",
				})
			}
		})

		// 查询单一(根据username查)
		auth.GET("/query", func(ctx *gin.Context) {
			// 打印请求体内容以调试
			// body, _ := ctx.GetRawData()
			// fmt.Println(string(body))
			var dataInfo entity.User
			if err := ctx.ShouldBindJSON(&dataInfo); err != nil {
				ctx.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "Invalid request body"})
				fmt.Println(err)
				return
			}
			username := dataInfo.Username
			var user entity.User
			if err := db.Table("user").Where("username = ?", username).First(&user).Error; err != nil {
				ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
					"code":    0,
					"message": "query failed",
				})
				fmt.Println(err)
			} else {
				ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
					"code":    1,
					"message": user,
				})
			}
		})

		// 查询全部(根据username查)
		auth.GET("/queryAll", func(ctx *gin.Context) {
			var dataInfo entity.User
			if err := ctx.ShouldBindJSON(&dataInfo); err != nil {
				ctx.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "Invalid request body"})
				return
			}
			username := dataInfo.Username
			var user []entity.User
			if err := db.Table("user").Where("username like ?", "%"+username+"%").Find(&user).Error; err != nil {
				ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
					"code":    0,
					"message": "queryAll failed",
				})
				fmt.Println(err)
			} else {
				ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
					"code":    1,
					"message": user,
				})
			}
		})

		// 修改
		auth.PUT("/update", func(ctx *gin.Context) {
			var dataInfo entity.User
			if err := ctx.ShouldBindJSON(&dataInfo); err != nil {
				ctx.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "Invalid request body"})
				return
			}
			username := dataInfo.Username
			password := dataInfo.Password
			var user entity.User
			userUpdate := entity.User{Username: username, Password: password}
			if err := db.Table("user").Where("username = ?", username).First(&user).Error; err != nil {
				ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
					"code":    0,
					"message": "no such user",
				})
				fmt.Println(err)
			} else {
				if err := db.Table("user").Where("username = ?", username).Updates(userUpdate).Error; err != nil {
					ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
						"code":    0,
						"message": "update failed",
					})
					fmt.Println(err)
				} else {
					ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
						"code":    1,
						"message": "update success",
					})
				}
			}
		})

		// 删除
		auth.DELETE("/delete", func(ctx *gin.Context) {
			var dataInfo entity.User
			if err := ctx.ShouldBindJSON(&dataInfo); err != nil {
				ctx.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": "Invalid request body"})
				return
			}
			username := dataInfo.Username
			var user entity.User
			if err := db.Table("user").Where("username = ?", username).First(&user).Error; err != nil {
				ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
					"code":    0,
					"message": "no such user",
				})
			} else {
				if err := db.Table("user").Where("username = ?", username).Delete(&user).Error; err != nil {
					ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
						"code":    0,
						"message": "delete failed",
					})
					fmt.Println(err)
				} else {
					ctx.AbortWithStatusJSON(http.StatusOK, gin.H{
						"code":    1,
						"message": "delete success",
					})
				}
			}
		})
	}
	return r
}

func InitDB() *gorm.DB {
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=true",
		config.AppConfig.Database.User,
		config.AppConfig.Database.Password,
		config.AppConfig.Database.Host,
		config.AppConfig.Database.Port,
		config.AppConfig.Database.Name,
		config.AppConfig.Database.CharSet)
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}
	return db
}
